namespace System
{
    public static class DelegateExceptionEx
    {
        #region Action

        public static Action TryCatch(this Action action, Action OnException = null)
        {
            return () =>
            {
                try
                {
                    action();
                } catch(Exception)
                {
                    if(OnException != null) OnException();
                }
            };
        }

        public static Action<T> TryCatch<T>(this Action<T> action, Action<T> OnException = null)
        {
            return t =>
            {
                try
                {
                    action(t);
                } catch(Exception)
                {
                    if(OnException != null) OnException(t);
                }
            };
        }

        public static Action TryCatch<TException>(this Action action, Action OnException = null)
            where TException : Exception
        {
            return () =>
            {
                try
                {
                    action();
                } catch(TException)
                {
                    if(OnException != null) OnException();
                }
            };
        }

        public static Action<T> TryCatch<T, TException>(this Action<T> action, Action<T> OnException = null)
            where TException : Exception
        {
            return t =>
            {
                try
                {
                    action(t);
                } catch(TException)
                {
                    if(OnException != null) OnException(t);
                }
            };
        }

        #endregion

        #region Func

        public static Func<T> TryCatch<T>(this Func<T> func, Func<T> OnException = null)
        {
            return () =>
            {
                try
                {
                    return func();
                } catch(Exception)
                {
                    return OnException == null ? default(T) : OnException();
                }
            };
        }

        public static Func<TIn, TOut> TryCatch<TIn, TOut>(this Func<TIn, TOut> func, Func<TIn, TOut> OnException = null)
        {
            return t =>
            {
                try
                {
                    return func(t);
                } catch(Exception)
                {
                    return OnException == null ? default(TOut) : OnException(t);
                }
            };
        }

        public static Func<T> TryCatch<T, TException>(this Func<T> func, Func<T> OnException = null)
            where TException : Exception
        {
            return () =>
            {
                try
                {
                    return func();
                } catch(TException)
                {
                    return OnException == null ? default(T) : OnException();
                }
            };
        }

        public static Func<TIn, TOut> TryCatch<TIn, TOut, TException>(this Func<TIn, TOut> func,
            Func<TIn, TOut> OnException = null)
            where TException : Exception
        {
            return t =>
            {
                try
                {
                    return func(t);
                } catch(TException)
                {
                    return OnException == null ? default(TOut) : OnException(t);
                }
            };
        }

        #endregion

    }
}